import 'dart:convert';
import 'dart:io';

import 'package:crypto/crypto.dart';
import 'package:ffmpeg_kit_flutter/ffmpeg_kit.dart';
import 'package:ffmpeg_kit_flutter/ffmpeg_session.dart';
import 'package:flutter_download_plugin/utils/video/video_prevew_info.dart';
import 'package:intl/intl.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;

class VideoUtils {
  static String YMD_HMS = "yyyy-MM-dd HH:mm:ss";

  ///根据url获取m3u8的基础信息
  static Future<VideoPreviewInfo> getVideoInfoByUrl({
    required String url,
  }) async {
    String command = "-protocol_whitelist file,http,https,tcp,tls"; //忽略协议验证
    command += " -i $url -hide_banner"; //指定路径
    FFmpegSession session = await FFmpegKit.execute(command);
    String? output = await session.getOutput();

    if (output != null) {
      return parseVideoInfo(url, output);
    }

    return VideoPreviewInfo(
      url: url,
      duration: 0,
      width: 0,
      height: 0,
      bitrate: 0,
    );
  }

  ///正则提取信息
  static VideoPreviewInfo parseVideoInfo(String url, String output) {
    VideoPreviewInfo info = VideoPreviewInfo(url: url);

    // 正则表达式提取时长 (秒)
    RegExp durationRegExp = RegExp(r'Duration: (\d+):(\d+):([\d.]+)');
    Match? durationMatch = durationRegExp.firstMatch(output);
    if (durationMatch != null) {
      int hours = int.parse(durationMatch.group(1)!);
      int minutes = int.parse(durationMatch.group(2)!);
      double seconds = double.parse(durationMatch.group(3)!);
      int totalSeconds = (hours * 3600 + minutes * 60 + seconds).toInt();

      // print('时长（秒）：$totalSeconds');
      info.duration = totalSeconds;
    }

    // 提取分辨率的正则表达式
    RegExp resolutionRegExp = RegExp(r'Video: .*?, .*?, (\d+)x(\d+)'); // 确保匹配在 Video: 后的分辨率
    Match? resolutionMatch = resolutionRegExp.firstMatch(output);
    if (resolutionMatch != null) {
      int width = int.parse(resolutionMatch.group(1)!);
      int height = int.parse(resolutionMatch.group(2)!);

      // print('分辨率：${width}x${height}');
      info.width = width;
      info.height = height;
    } else {
      print('未找到分辨率信息');
    }
    return info;
  }

  ///得到m3u8链接的封面图[url]最终媒体的url地址
  ///如果已经下载过的话不会重复下载
  static Future<String> getVideoCoverByPreviewInfo({required VideoPreviewInfo info}) async {
    Directory directory = await getTemporaryDirectory();

    String dir = "${directory.path}/previewImage";
    Directory(dir).createSync(recursive: true);

    String fileName = generateMd5(info.url);
    String savePath = "$dir/$fileName.jpg";
    File file = File(savePath);
    if (file.existsSync()) {
      return savePath;
    }

    String downloadUrl = info.url;

    int captureSecond = 0; //截图的时间点
    if (info.duration > 3) {
      captureSecond = 3;
    } else if (info.duration > 2) {
      captureSecond = 2;
    } else if (info.duration >= 1) {
      captureSecond = 1;
    } else {
      captureSecond = 0;
    }

    String command = "-protocol_whitelist file,http,https,tcp,tls"; //忽略协议验证
    command += " -ss 00:00:0$captureSecond"; //截取的时间 //由于部分m3u8由于帧率的原因可能在指定时间点并没有关键帧所有这里有可能没有返回图片
    command += " -i $downloadUrl"; //指定路径
    command += " -vframes 1 -q:v 15  $savePath"; //取该时间的首帧";
    FFmpegSession session = await FFmpegKit.execute(command);

    final returnCode = await session.getReturnCode();
    //
    // print(playList.durationUs);

    return savePath;
  }

  ///得到m3u8链接的封面图[url]最终媒体的url地址
  ///如果已经下载过的话不会重复下载
  static Future<String> getVideoCoverByUrl({required String url}) async {
    Directory directory = await getApplicationDocumentsDirectory();

    String dir = "${directory.path}/previewImage";
    Directory(dir).createSync(recursive: true);

    String fileName = generateMd5(url);

    String savePath = "$dir/$fileName.jpg";
    File file = File(savePath);
    if (file.existsSync()) {
      return savePath;
    }

    int captureSecond = 0; //截图的时间点

    String command = "-protocol_whitelist file,http,https,tcp,tls"; //忽略协议验证
    command += " -ss 00:00:0$captureSecond"; //截取的时间 //由于部分m3u8由于帧率的原因可能在指定时间点并没有关键帧所有这里有可能没有返回图片
    command += " -i $url"; //指定路径
    command += " -vframes 1 -q:v 15  ${savePath}"; //取该时间的首帧";
    FFmpegSession session = await FFmpegKit.execute(command);

    final returnCode = await session.getReturnCode();
    //
    // print(playList.durationUs);

    return savePath;
  }

  ///提取文件的后缀
  static String getSuffix(String url) {
    try {
      int index = url.lastIndexOf(".");
      if (index >= 0) {
        return url.substring(index, url.length);
      }

      return ""; // 未提取到文件名时返回 "未知"
    } catch (e) {
      return ""; // 捕获异常并返回 "未知"
    }
  }

  /// 将字符串转换为 MD5 哈希值
  static String generateMd5(String input) {
    // 使用 utf8 编码字符串
    List<int> bytes = utf8.encode(input);

    // 计算 MD5 哈希值
    Digest digest = md5.convert(bytes);

    // 将哈希值转换为十六进制字符串
    return digest.toString();
  }

  /// 时间戳转本地时间格式
  /// [timestamp] 是时间戳（毫秒级）
  /// [format] 是时间格式，例如 "yyyy-MM-dd HH:mm:ss"
  /// 返回本地时间字符串
  static String timestampToLocalTime(int timestamp, {String format = "yyyy-MM-dd HH:mm:ss"}) {
    try {
      DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(timestamp, isUtc: true).toLocal();
      return DateFormat(format).format(dateTime);
    } catch (e) {
      print("Error converting to local time: $e");
      return "1970-1-1 00:00:00";
    }
  }

  /// 获取文件名（包含扩展名）
  static String getFileName(String filePath) {
    return path.basename(filePath);
  }

  /// 获取文件名（不包含扩展名）
  static String getFileNameWithoutExtension(String filePath) {
    return path.basenameWithoutExtension(filePath);
  }

  /// 获取文件扩展名
  static String getFileExtension(String filePath) {
    return path.extension(filePath);
  }

  /// 获取文件所在目录
  static String getDirectory(String filePath) {
    return path.dirname(filePath);
  }

// 工具方法：计算下载速度并格式化显示
  static String calculateSpeed(int speed) {
    // 根据速度大小选择合适的单位
    if (speed < 1024) {
      return '${speed.toStringAsFixed(1)} B/s'; // 字节/秒
    } else if (speed < 1024 * 1024) {
      double speedInKB = speed / 1024;
      return '${speedInKB.toStringAsFixed(1)} KB/s'; // KB/秒
    } else {
      double speedInMB = speed / (1024 * 1024);
      return '${speedInMB.toStringAsFixed(1)} MB/s'; // MB/秒
    }
  }

  ///把时间秒数转换为时间格式例如  02:32
  static String formatDuration(double seconds) {
    Duration duration = Duration(seconds: seconds.toInt());

    // 提取时、分、秒
    int hours = duration.inHours;
    int minutes = duration.inMinutes.remainder(60);
    int secs = duration.inSeconds.remainder(60);

    // 格式化字符串，如果有小时则显示 hh:mm:ss，否则显示 mm:ss
    if (hours > 0) {
      return '${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}:${secs.toString().padLeft(2, '0')}';
    } else {
      return '${minutes.toString().padLeft(2, '0')}:${secs.toString().padLeft(2, '0')}';
    }
  }

  ///转换显示文件格式
  static String formatFileSize(int fileSize) {
    if (fileSize < 1024) {
      return "$fileSize B";
    } else if (fileSize < 1024 * 1024) {
      return "${(fileSize / 1024).toStringAsFixed(2)} KB";
    } else if (fileSize < 1024 * 1024 * 1024) {
      return "${(fileSize / (1024 * 1024)).toStringAsFixed(2)} MB";
    } else {
      return "${(fileSize / (1024 * 1024 * 1024)).toStringAsFixed(2)} GB";
    }
  }
}
